#include "WebElement.h"
#include "WebPage.h"

namespace SpiderWebKitClient {

WebElement::WebElement()
    : m_caller(NULL)
    , m_ref(0)
{
}

WebElement::WebElement(long element, long pageRef, WebKitCaller *caller)
    : m_caller(caller)
    , m_ref(element)
    , m_pageRef(pageRef)
{
}

WebElement::~WebElement()
{
}

std::list<WebElement> WebElement::getChildsByCssSelector(std::string query)
{
    std::list<long> ret;
    std::list<WebElement> elements;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(query);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_VOID_GETCHILDSBYCSSSELECTOR, arglist);
    ret = m_caller->getReturnLongArrayValue(retMessage);

    std::list<long>::iterator it;
    for(it = ret.begin(); it != ret.end(); it ++) {
        WebElement e(*it, m_pageRef, m_caller);
        elements.push_back(e);
    }

    return elements;
}

std::string WebElement::getTagName()
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETTAGNAME_LONG_REF, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

std::string WebElement::getAttribute(std::string name)
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(name);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETATTRIBUTE_LONG_REF_STRING_NAME, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

void WebElement::setAttribute(std::string name, std::string value)
{
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(name);
    arglist.push_back(value);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_VOID_SETATTRIBUTE, arglist);
}

void WebElement::removeAttribute(std::string name)
{
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(name);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_VOID_REMOVEATTRIBUTE, arglist);
}

std::string WebElement::getProperty(std::string name)
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(name);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETPROPERTY_LONG_REF_STRING_NAME, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

std::string WebElement::getText()
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETTEXT_LONG_REF, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

std::string WebElement::getValue()
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETVALUE_LONG_REF, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

long WebElement::sendKeys(std::string type, long keys)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string val = boost::lexical_cast<std::string>(keys);
    std::string syc = boost::lexical_cast<std::string>(0);
    arglist.push_back(arg);
    arglist.push_back(type);
    arglist.push_back(val);
    arglist.push_back(syc);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SENDKEYS_LONG_REF_STRING_TYPE_LONG_KEYS, arglist);
    long page;
    ret = m_caller->getReturnPageValue(retMessage, &page);

    return ret;
}

long WebElement::type(std::string val)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(val);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_TYPE_LONG_REF_STRING_VAL, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::setValue(std::string val)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    arglist.push_back(val);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SETVALUE_LONG_REF_STRING_VAL, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::submit()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SUBMIT_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::click()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string asy = boost::lexical_cast<std::string>(0);
    arglist.push_back(arg);
    arglist.push_back(asy);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_CLICK_LONG_REF, arglist);
    long page;
    ret = m_caller->getReturnPageValue(retMessage, &page);

    return ret;
}

long WebElement::reset()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_RESET_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::toggle()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_TOGGLE_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::focus()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_FOCUS_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::selected()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SELECTED_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::setSelected(bool selected)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string sel = boost::lexical_cast<std::string>(selected);
    arglist.push_back(arg);
    arglist.push_back(sel);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SETSELECTED_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::checked()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_CHECKED_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::setChecked(bool checked)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string sel = boost::lexical_cast<std::string>(checked);
    arglist.push_back(arg);
    arglist.push_back(sel);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SETCHECKED_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::selectOptionByIndex(int index)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string id = boost::lexical_cast<std::string>(index);
    arglist.push_back(arg);
    arglist.push_back(id);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_SELECTOPTIONBYINDEX_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

long WebElement::stale()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_STALE_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

bool WebElement::isVisible()
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_BOOL_ISVISIBLE_LONG_REF, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret == 0 ? false : true;
}

long WebElement::drag(int toX, int toY, int duration)
{
    long ret = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    std::string tox = boost::lexical_cast<std::string>(toX);
    std::string toy = boost::lexical_cast<std::string>(toY);
    std::string dur = boost::lexical_cast<std::string>(duration);
    arglist.push_back(arg);
    arglist.push_back(tox);
    arglist.push_back(toy);
    arglist.push_back(dur);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_LONG_DRAG_LONG_REF_INT_TOX_INT_TOY_INT_DURATION, arglist);
    ret = m_caller->getReturnLongValue(retMessage);

    return ret;
}

WERect WebElement::getRect()
{
    int x = 0, y = 0, w = 0, h = 0;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_RECT_GETRECT_LONG_REF, arglist);
    m_caller->getReturnRectValue(retMessage, &x, &y, &w, &h);

    WERect ret = {x, y, w, h};

    return ret;
}

std::string WebElement::getInnerXml()
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETINNERXML_LONG_REF, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

std::string WebElement::getOuterXml()
{
    std::string ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(m_pageRef, WEBELEMENT_STRING_GETOUTERXML_LONG_REF, arglist);
    ret = m_caller->getReturnStringValue(retMessage);

    return ret;
}

bool WebElement::getImageBuffer(std::vector<char> &output)
{
    bool ret;
    std::list<std::string> arglist;

    std::string arg = boost::lexical_cast<std::string>(ref());
    arglist.push_back(arg);
    std::string retMessage = m_caller->webKitCall(ref(), WEBPAGE_STRING_RENDER_IMAGE_BASE64, arglist);
    ret = m_caller->getReturnBufferValue(retMessage, output);

    return ret;
}

bool WebElement::waitForInnerXml(unsigned int times)
{
    if (isFailed())
        return false;

    unsigned int count = times;
    while (count) {
        std::string innerxml = getInnerXml();
        if (innerxml == "") {
            usleep(200000);
            count --;
        } else
            return true;
    }

    return false;
}

bool WebElement::isFailed()
{
    return m_caller->failed();
}

} // namespace SpiderWebKitClient

